/*
 * Flashlib - QB9 common Flash library
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package com.qb9.flashlib.easing
{
	import com.qb9.flashlib.tasks.*;

	/**
	 * Generic tween task. Allows to animate (tween) one or more properties of any given object.
	 *
	 * <p>Example: tween the x, y, and alpha properties of a DisplayObject for 1.3 seconds:
	 * <pre>
	 * var tween1:Tween = new Tween(sprite1, 1300, {x:30, y:40, alpha:0.3});
	 * </pre>
	 * </p>
	 *
	 * <p>Another example: tween the x property for 0.3 seconds, with an "easeout" transition.
	 * Also, make sure that when the task starts, x is set to 10:
	 * <pre>
	 * var tween2:Tween = new Tween(sprite2, 300, {x:40}, {from: {x:10}, transition: "easeout"});
	 * </pre>
	 * </p>
	 *
	 * @see com.qb9.flashlib.tasks.TaskRunner
	 */
	public class Tween extends Ease
	{
		protected var obj:Object;
		protected var src:Object;
		protected var dest:Object;
		protected var options:Object;
		
		/**
		 * Create a Tween task.
		 *
		 * @param obj The target object whos attributes will be modified.
		 * @param duration Duration (in milliseconds) for the task.
		 * @param dest Attributes to be modified and their destination values.
		 * @param options Optional parameters for the tween: <ul>
		 *   <li>relative: If set to <code>true</code>, all destination values will be relative to their respective initial values.</li>
		 *   <li>from: An object containing initialization values for some target attributes.</li>
		 *   <li>transition: Any identifier accepted by <code>Easing.getFunction()</code>. Examples: "linear" (default), "easeIn", "easeOut", "easeInOut", "bounceEaseIn", etc.</li>
		 *   <li>updateFunction: A function that will be called on each time step. It will be passed two parameters: the target object, and the current tweened value (normally between 0 and 1).</li>
		 * </ul>
		 *
		 * @see TaskRunner
		 * @see Ease
		 * @see Easing
		 */
		public function Tween(obj:Object, duration:int, dest:Object, options:Object = null)
		{
			this.options = options || {};
			super(updateFunction, duration, 0.0, 1.0, this.options.transition);
			this.dest = dest;
			this.obj = obj;
			this.src = this.options.from || {};

			this.dest = dest;
		}
		
		/** @inheritDoc */
		public override function clone():ITask
		{
			return new Tween(obj, duration, dest, options);
		}

		/** @inheritDoc */
		public override function start():void
		{
			for (var attr:String in this.dest)
			{
				if (this.src[attr] == null)
					this.src[attr] = Number(this.obj[attr]);
				if (this.options.relative)
					dest[attr] += this.src[attr];
			}
			super.start();
		}

		protected function tweenedAttribute(attr:String, tween:Number):Number
		{
			var from:Number = this.src[attr];
			var dist:Number = Number(this.dest[attr]) - from;
			return from + tween * dist;
		}

		protected function updateFunction(tween:Number):void
		{
			for (var attr:String in this.dest)
				this.obj[attr] = this.tweenedAttribute(attr, tween);
			if (this.options.updateFunction != null)
				this.options.updateFunction(obj, tween);
		}
	}
}

